package com.cskaoyan.threadsafe.edition2;

/*
     第一个问题: 同一张票售卖了多次
     first售出了第100张票
     third售出了第100张票

     第二个问题: 卖除了不存在的票(第0张票)
     first售出了第1张票
     second售出了第0张票

     上述两个问题，对应的就是多线程中常见的两个问题:  多买 和 超卖问题

     不论是超卖问题，多卖问题，都属于多线程的数据安全问题: 多线程环境下，在多个线程中访问共享的数据，访问到了错误的数据


 */
public class Demo1 {

    public static void main(String[] args) {

        // 创建售票任务对象
        SalesTask salesTask = new SalesTask();

        Thread firstWindow = new Thread(salesTask,"first");
        Thread secondWindow = new Thread(salesTask, "second");
        Thread thirdWindow = new Thread(salesTask, "third");

        // 启动三个线程，模拟三个窗口售票
        firstWindow.start();
        secondWindow.start();
        thirdWindow.start();
    }
}

class SalesTask implements Runnable {

    //待售卖的100张票
    // 普通成员变量
    int tickets = 100;

    @Override
    public void run() {
        while (tickets > 0) {
            // sleep方法模拟售票的延迟
            // 超卖问题: 假设 tickets值1
            // first窗口1线程，判断发现，tickets=1 > 0,于是进入while循环准备收票, 刚刚进入while循环，又发生线程切换
            // second窗口2线程，判断发现，tickets=1 > 0, 于是也进入while循环，准备卖票
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            // 有票则售票
            // 多卖问题
             // 前提: ticket--  1. 读取tickets变量的值  2. tickets - 1  3. tickets - 1 结果赋值给tickets
            // first, 窗口1线程，执行 "first售出了第100"(假设此时还没有来及修改tickets的值)，发生了线程切换
            // third，窗口3线程，执行 "third售出了第100"...
            System.out.println(Thread.currentThread().getName() + "售出了第" + tickets-- + "张票");
        }

    }
}


